package com.lonely.product.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lonely.common.core.domain.BaseEntity;
import com.lonely.common.core.domain.StatusInfo;
import com.lonely.common.core.page.Condition;
import com.lonely.common.enums.DataScope;
import com.lonely.common.threadlocals.DataPermissionThreadLocal;
import com.lonely.common.utils.SecurityUtils;
import com.lonely.common.utils.enums.ExtractStatusInfoUtil;
import com.lonely.goods.enums.GoodsEnum;
import com.lonely.order.domain.entity.SysOrder;
import com.lonely.order.domain.entity.SysOrderSecondProcess;
import com.lonely.order.domain.entity.SysOrderSplit;
import com.lonely.order.enums.OrderSecondProcessEnum;
import com.lonely.order.service.IOrderSecondProcessService;
import com.lonely.order.service.IOrderService;
import com.lonely.order.service.IOrderSplitService;
import com.lonely.product.domain.dto.sewing.QueryOrderSewingPageDTO;
import com.lonely.product.domain.dto.sewing.SewingCompletedDTO;
import com.lonely.product.domain.dto.sewing.StartSewingDTO;
import com.lonely.product.domain.entity.SysOrderSewing;
import com.lonely.product.domain.vo.sewing.QueryOrderSewingPageVO;
import com.lonely.product.enums.OrderSewingEnum;
import com.lonely.product.mapper.SysOrderSewingMapper;
import com.lonely.product.service.ICuttingBedService;
import com.lonely.product.service.IOrderPostFinishingService;
import com.lonely.product.service.IOrderSewingService;
import com.lonely.system.domain.entity.SysFactory;
import com.lonely.system.enums.SysFactoryEnum;
import com.lonely.system.service.ISysFactoryService;
import com.lonely.system.utils.AuthUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author : 黄志标
 * @date: 2025/8/12 9:40
 * @description: 订单车缝服务实现类
 */
@Service
@Slf4j
public class OrderSewingServiceImpl extends ServiceImpl<SysOrderSewingMapper, SysOrderSewing> implements IOrderSewingService {

    @Autowired
    private IOrderSecondProcessService orderSecondProcessService;

    @Autowired
    private IOrderService orderService;

    @Autowired
    private IOrderSplitService orderSplitService;

    @Autowired
    private ISysFactoryService sysFactoryService;

    @Autowired
    private IOrderPostFinishingService orderPostFinishingService;

    @Autowired
    private ICuttingBedService cuttingBedService;


    /**
     * 生成订单车缝数据
     *
     * @param produceOrderId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createOrderSewing(Long produceOrderId) {
        // 判断是否已存在车缝数据
        if (isExistOrderSewing(produceOrderId)) {
            log.info("该订单已存在车缝数据");
            return;
        }

        // 判断是否存在二次工艺数据
        if (this.orderSecondProcessService.isExistOrderSecondProcess(produceOrderId)) {
            // 判断是否存在裁片二次工艺待确认的数据
            if (this.orderSecondProcessService.isExistCuttingSecondProcessNeedConfirm(produceOrderId)) {
                // 存在待确认的二次工艺，则逻辑中止，等待二次工艺确认后再生成车缝数据
                log.info("存在待确认的二次工艺，请等待二次工艺确认后再生成车缝数据");
                return;
            }

            // 判断二次工艺中裁片二次工艺为是的是否都已回料了
            if (!this.orderSecondProcessService.isAllCuttingSecondProcessReturned(produceOrderId)) {
                log.info("存在未回料的裁片二次工艺，请等待裁片二次工艺回料后再生成车缝数据");
                return;
            }
        }

        // 二次工艺数据校验完成，下面判断该订单分单状态
        SysOrderSplit workshopSplit = this.orderSplitService.getWorkshopSplit(produceOrderId);
        if (workshopSplit != null) {
            SysOrderSewing defaultOrderSewing = this.generatorDefaultOrderSewing(produceOrderId);

            // 判断是总厂还是外发厂
            SysFactory sysFactory = this.sysFactoryService.getById(workshopSplit.getFactoryId());
            Assert.notNull(sysFactory, "工厂不存在");
            defaultOrderSewing.setFactoryId(sysFactory.getId());

            SysFactoryEnum.FactoryType factoryType = SysFactoryEnum.FactoryType.getInstance(sysFactory.getType());
            if (factoryType == SysFactoryEnum.FactoryType.OWN) {
                defaultOrderSewing.setType(OrderSewingEnum.TypeEnum.GENERAL_FACTORY.getValue());
            }
            if (factoryType == SysFactoryEnum.FactoryType.COOPERATIVE) {
                defaultOrderSewing.setType(OrderSewingEnum.TypeEnum.OUTSOURCING_FACTORY.getValue());
            }

            this.save(defaultOrderSewing);

        } else {
            // 未分单，分别生成总厂车缝类型和外发车缝的数据
            this.saveUndividedOrderSewing(produceOrderId);
        }

    }

    /**
     * 车缝分页查询
     *
     * @param queryDto
     * @return
     */
    @Override
    public Page<QueryOrderSewingPageVO> page(QueryOrderSewingPageDTO queryDto) {
        DataPermissionThreadLocal.setDataPermission(DataScope.ORDER_FACTORY, "o.factory_permission");
        Page<QueryOrderSewingPageVO> page = Condition.page(queryDto);
        return super.getBaseMapper().page(page, queryDto, OrderSewingEnum.TypeEnum.GENERAL_FACTORY.getValue());
    }

    /**
     * 获取状态信息
     *
     * @param queryDto
     * @return
     */
    @Override
    public List<StatusInfo> getStatusInfo(QueryOrderSewingPageDTO queryDto) {
        // 去除状态过滤
        queryDto.setSewingStatus(null);
        // 添加数据权限过滤
        String factoryPermissionsJsonStr = AuthUtil.getLoginUserFactoryPermissionsJsonStr();
        List<StatusInfo> statusTotals = super.getBaseMapper().getStatusTotals(queryDto, OrderSewingEnum.TypeEnum.GENERAL_FACTORY.getValue(), factoryPermissionsJsonStr);
        return ExtractStatusInfoUtil.extractStatusInfos(statusTotals, OrderSewingEnum.StatusEnum.values());
    }

    /**
     * 外发车缝分页查询
     *
     * @param queryDto
     * @return
     */
    @Override
    public Page<QueryOrderSewingPageVO> outsourcePage(QueryOrderSewingPageDTO queryDto) {
        DataPermissionThreadLocal.setDataPermission(DataScope.ORDER_FACTORY, "o.factory_permission");
        Page<QueryOrderSewingPageVO> page = Condition.page(queryDto);
        return super.getBaseMapper().page(page, queryDto, OrderSewingEnum.TypeEnum.OUTSOURCING_FACTORY.getValue());
    }

    /**
     * 获取外发车缝状态信息
     *
     * @param queryDto
     * @return
     */
    @Override
    public List<StatusInfo> getOutsourceStatusInfo(QueryOrderSewingPageDTO queryDto) {
        // 去除状态过滤
        queryDto.setSewingStatus(null);
        // 添加数据权限过滤
        String factoryPermissionsJsonStr = AuthUtil.getLoginUserFactoryPermissionsJsonStr();
        List<StatusInfo> statusTotals = super.getBaseMapper().getStatusTotals(queryDto, OrderSewingEnum.TypeEnum.OUTSOURCING_FACTORY.getValue(), factoryPermissionsJsonStr);
        return ExtractStatusInfoUtil.extractStatusInfos(statusTotals, OrderSewingEnum.StatusEnum.values());
    }

    /**
     * 开始车缝
     *
     * @param requestDto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void startSewing(StartSewingDTO requestDto) {
        super.update(new LambdaUpdateWrapper<SysOrderSewing>()
                .eq(SysOrderSewing::getId, requestDto.getSewingId())
                .eq(SysOrderSewing::getType, requestDto.getSewingType())
                .eq(SysOrderSewing::getStatus, OrderSewingEnum.StatusEnum.TO_BE_SEWING.getStatus())
                .set(SysOrderSewing::getStatus, OrderSewingEnum.StatusEnum.IN_SEWING_SEAM.getStatus())
                .set(SysOrderSewing::getSewingStartTime, new Date())
                .set(SysOrderSewing::getStartSewingQuantity, requestDto.getStartSewingQuantity())
                .set(SysOrderSewing::getUpdateBy, SecurityUtils.getUserId())
        );
    }

    /**
     * 订单分单后置处理
     *
     * @param produceOrderIds
     * @param sysFactory
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderSplitAfterProcess(List<Long> produceOrderIds, SysFactory sysFactory) {
        if (CollUtil.isEmpty(produceOrderIds)) {
            return;
        }

        // 获取工厂类型
        SysFactoryEnum.FactoryType factoryType = SysFactoryEnum.FactoryType.getInstance(sysFactory.getType());

        // 定义当前工厂类型对应的车缝类型和需删除的类型
        OrderSewingEnum.TypeEnum keepType;
        OrderSewingEnum.TypeEnum removeType;
        if (SysFactoryEnum.FactoryType.OWN.equals(factoryType)) {
            // 总厂：保留总厂类型，删除外发类型
            keepType = OrderSewingEnum.TypeEnum.GENERAL_FACTORY;
            removeType = OrderSewingEnum.TypeEnum.OUTSOURCING_FACTORY;
        } else {
            // 外发厂：保留外发类型，删除总厂类型
            keepType = OrderSewingEnum.TypeEnum.OUTSOURCING_FACTORY;
            removeType = OrderSewingEnum.TypeEnum.GENERAL_FACTORY;
        }

        for (Long produceOrderId : produceOrderIds) {
            // 获取当前订单的未完工的车缝数据
            List<SysOrderSewing> orderSewings = super.list(new LambdaQueryWrapper<SysOrderSewing>()
                    .eq(SysOrderSewing::getProduceOrderId, produceOrderId)
                    .ne(SysOrderSewing::getStatus, OrderSewingEnum.StatusEnum.COMPLETED.getStatus())
            );
            if (CollUtil.isEmpty(orderSewings)) {
                log.debug("当前订单无未完工的车缝数据");
                continue;
            }

            if (CollUtil.size(orderSewings) == 1) {
                // 非未分单状态的车缝数据
                SysOrderSewing sysOrderSewing = orderSewings.get(0);

                // 判断是否修改了工厂
                if (Objects.equals(sysOrderSewing.getFactoryId(), sysFactory.getId())) {
                    // 没有改变工厂,不做改变
                    log.debug("当前订单车缝数据未改变工厂,不做调整...");
                    continue;
                }

                // 修改了工厂，更新工厂id和重置订单状态
                sysOrderSewing.setFactoryId(sysFactory.getId());
                sysOrderSewing.setType(keepType.getValue());
                sysOrderSewing.setStartSewingQuantity(null);
                sysOrderSewing.setStatus(OrderSewingEnum.StatusEnum.TO_BE_SEWING.getStatus());
                super.updateById(sysOrderSewing);
            } else {
                // 有多条车缝数据，即都是未分单的数据

                // 查找需要保留并更新 factoryId 的车缝记录
                SysOrderSewing targetSewing = orderSewings.stream()
                        .filter(x -> Objects.equals(x.getType(), keepType.getValue()))
                        .findFirst()
                        .orElse(null);
                if (targetSewing != null) {
                    targetSewing.setFactoryId(sysFactory.getId());
                    targetSewing.setStartSewingQuantity(null);
                    targetSewing.setStatus(OrderSewingEnum.StatusEnum.TO_BE_SEWING.getStatus());
                    super.updateById(targetSewing);
                }

                // 收集需要删除的车缝 ID（对应 removeType）
                List<Long> idsToRemove = orderSewings.stream()
                        .filter(x -> Objects.equals(x.getType(), removeType.getValue()))
                        .map(BaseEntity::getId)
                        .collect(Collectors.toList());
                if (CollUtil.isNotEmpty(idsToRemove)) {
                    super.removeByIds(idsToRemove);
                }
            }
        }
    }

    /**
     * 车缝完工
     *
     * @param requestDto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sewingCompleted(SewingCompletedDTO requestDto) {
        // 生成后整数据
        SysOrderSewing orderSewing = super.getOne(new LambdaQueryWrapper<SysOrderSewing>()
                .eq(SysOrderSewing::getId, requestDto.getSewingId())
                .eq(SysOrderSewing::getType, requestDto.getSewingType())
                .eq(SysOrderSewing::getStatus, OrderSewingEnum.StatusEnum.IN_SEWING_SEAM.getStatus())
        );
        Assert.notNull(orderSewing, "未找到车缝数据");

        orderSewing.setStatus(OrderSewingEnum.StatusEnum.COMPLETED.getStatus());
        orderSewing.setSewingEndTime(new Date());
        orderSewing.setCompletedSewingQuantity(requestDto.getCompletedSewingQuantity());
        orderSewing.setUpdateBy(SecurityUtils.getUserId());
        super.updateById(orderSewing);

        // 修改订单状态为尾部中
        this.orderService.updateOrderStatusToInTheTail(orderSewing.getOrderId());

        // 车缝完工后 后置处理生成后整数据
        this.orderPostFinishingService.createOrderPostFinishing(Convert.toLong(orderSewing.getProduceOrderId()));

    }

    /**
     * 获取默认的开始车缝数
     * 逻辑：如果该订单没有二次工艺，则将裁床书作为车缝数默认展示。如果存在二次工艺且是裁片二次工艺，则取裁片二次工艺已回料数作为车缝数默认展示。
     *
     * @param sewingId
     * @return
     */
    @Override
    public String getDefaultStartSewingQuantity(Long sewingId) {
        SysOrderSewing orderSewing = super.getById(sewingId);
        Assert.notNull(orderSewing, "未找到该车缝数据");

        // 判断是否存在二次工艺
        if (!this.orderSecondProcessService.isExistOrderSecondProcess(Convert.toLong(orderSewing.getProduceOrderId()))) {
            // 不存在二次工艺，则获取裁床数
            return Convert.toStr(this.cuttingBedService.getCuttingBedQuantity(Convert.toLong(orderSewing.getProduceOrderId())));
        } else {
            // 存在二次工艺，获取对应的二次工艺数据
            List<SysOrderSecondProcess> orderSecondProcesses = this.orderSecondProcessService.list(new LambdaQueryWrapper<SysOrderSecondProcess>()
                    .eq(SysOrderSecondProcess::getProduceOrderId, orderSewing.getProduceOrderId())
                    .eq(SysOrderSecondProcess::getType, GoodsEnum.GoodsSecondProcessTypeEnum.DOUGH_AND_AUXILIARY_MATERIALS.getType())
                    .eq(SysOrderSecondProcess::getCuttingSecondProcess, OrderSecondProcessEnum.CuttingSecondProcessEnum.IS.getValue())
                    .eq(SysOrderSecondProcess::getStatus, OrderSecondProcessEnum.StatusEnum.ALREADY_RETURN_MATERIAL.getStatus())
            );
            return Convert.toStr(orderSecondProcesses.stream().map(SysOrderSecondProcess::getRecycledMaterialsQuantity).filter(Objects::nonNull)
                    .mapToInt(x -> x).sum());

        }
    }

    /**
     * 获取默认的车缝完工数
     * 逻辑: 默认取值为当前车缝数
     *
     * @param sewingId
     * @return
     */
    @Override
    public String getDefaultCompletedSewingQuantity(Long sewingId) {
        SysOrderSewing orderSewing = super.getById(sewingId);
        Assert.notNull(orderSewing, "未找到该车缝数据");
        return Convert.toStr(orderSewing.getStartSewingQuantity());
    }

    /**
     * 未分单的车缝数据入库
     *
     * @param produceOrderId
     */
    private void saveUndividedOrderSewing(Long produceOrderId) {
        // 总厂未分单的车缝数据
        SysOrderSewing generalFactorySewing = this.generatorDefaultOrderSewing(produceOrderId);
        generalFactorySewing.setType(OrderSewingEnum.TypeEnum.GENERAL_FACTORY.getValue());
        generalFactorySewing.setStatus(OrderSewingEnum.StatusEnum.UNDIVIDED_ORDERS.getStatus());
        generalFactorySewing.setFactoryId(null);
        super.save(generalFactorySewing);

        // 外发厂未分单的车缝数据
        SysOrderSewing outsourceFactorySewing = this.generatorDefaultOrderSewing(produceOrderId);
        outsourceFactorySewing.setType(OrderSewingEnum.TypeEnum.OUTSOURCING_FACTORY.getValue());
        outsourceFactorySewing.setStatus(OrderSewingEnum.StatusEnum.UNDIVIDED_ORDERS.getStatus());
        outsourceFactorySewing.setFactoryId(null);
        super.save(outsourceFactorySewing);
    }


    /**
     * 构架默认的车缝数据
     *
     * @param produceOrderId
     * @return
     */
    private SysOrderSewing generatorDefaultOrderSewing(Long produceOrderId) {
        SysOrder sysOrder = this.orderService.getOne(new LambdaQueryWrapper<SysOrder>().eq(SysOrder::getProduceOrderId, produceOrderId));
        Assert.notNull(sysOrder, "订单不存在");

        SysOrderSewing sysOrderSewing = new SysOrderSewing();
        sysOrderSewing.setOrderId(sysOrder.getId());
        sysOrderSewing.setProduceOrderId(Convert.toStr(produceOrderId));
        sysOrderSewing.setType(null);
        sysOrderSewing.setFactoryId(null);
        sysOrderSewing.setSewingStartTime(null);
        sysOrderSewing.setSewingEndTime(null);
        sysOrderSewing.setStartSewingQuantity(null);
        sysOrderSewing.setCompletedSewingQuantity(null);
        sysOrderSewing.setCreateBy(SecurityUtils.getUserId());
        sysOrderSewing.setUpdateBy(SecurityUtils.getUserId());
        return sysOrderSewing;
    }


    /**
     * 判断是否已存在车缝数据
     *
     * @param produceOrderId
     * @return
     */
    private boolean isExistOrderSewing(Long produceOrderId) {
        int count = super.count(new LambdaQueryWrapper<SysOrderSewing>()
                .eq(SysOrderSewing::getProduceOrderId, produceOrderId)
        );
        return count > 0;
    }

}
